package com.hd.trans.widgets.views;

import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.DrawableContainer;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.LinearInterpolator;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RawRes;
import androidx.appcompat.widget.AppCompatImageView;

import com.github.penfeizhou.animation.apng.APNGDrawable;
import com.github.penfeizhou.animation.loader.ResourceStreamLoader;

import java.util.HashMap;
import java.util.concurrent.atomic.AtomicInteger;

public class AnimationImageView extends AppCompatImageView {
    private final HashMap<AnimationType,ObjectAnimator> mAnimators = new HashMap<>();

    private boolean isSysAutoPause = false;
    private boolean isSysAutoCancel = false;

    private AnimationType curAnimationType = null;

    public AnimationImageView(@NonNull Context context) {
        this(context,null);
    }
    public AnimationImageView(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }
    public AnimationImageView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    /**
     * 开始播放帧动画（需将图片源设置为Animatable）
     */
    public void startDrawableAnimation(){
        if (isPlaying(AnimationType.FRAME))
            return;

        //先取消其它的动画
        if (curAnimationType != AnimationType.FRAME) {
            cancelAnimation();
        }

        Animatable animation = getAnimationDrawable();

        if (animation == null)
            return;

        curAnimationType = AnimationType.FRAME;

        if (isShown()){
            animation.start();
        }
        else {
            if (getVisibility() == VISIBLE){
                AtomicInteger tryCount = new AtomicInteger(3);
                Runnable tryStartRunnable = new Runnable(){
                    @Override
                    public void run() {
                        if (isShown()){
                            animation.start();
                        }
                        else {
                            if (tryCount.getAndAdd(-1) > 0){
                                postDelayed(this,100);
                            }
                            else {
                                isSysAutoPause = true;
                            }
                        }
                    }
                };
                post(tryStartRunnable);
            }
            else {
                isSysAutoPause = true;
            }
        }
    }

    public void startRotateAnimation(){
        startRotateAnimation(1000);
    }

    private void startAnimator(ObjectAnimator animator){
        if (isShown()){
            if (animator.isPaused()){
                animator.resume();
            }
            else {
                animator.start();
            }
        }
        else {
            if (getVisibility() == VISIBLE){
                AtomicInteger tryCount = new AtomicInteger(3);
                Runnable tryStartRunnable = new Runnable() {
                    @Override
                    public void run() {
                        if (isShown()){
                            if (animator.isPaused()){
                                animator.resume();
                            }
                            else {
                                animator.start();
                            }
                        }
                        else {
                            if (tryCount.getAndAdd(-1) > 0){
                                postDelayed(this,100);
                            }
                            else {
                                isSysAutoPause = true;
                            }
                        }
                    }
                };
                post(tryStartRunnable);
            }
            else {
                isSysAutoPause = true;
            }
        }
    }

    /**
     * 开始播放旋转动画
     */
    public void startRotateAnimation(long duration){
        if (isPlaying(AnimationType.ROTATE))
            return;

        //先取消其它的动画
        if (curAnimationType != AnimationType.ROTATE) {
            cancelAnimation();
        }

        ObjectAnimator rotateAnimator = mAnimators.get(AnimationType.ROTATE);

        if (rotateAnimator == null){
            rotateAnimator = ObjectAnimator.ofFloat(this,ROTATION,0f,360f);
            rotateAnimator.setRepeatCount(ValueAnimator.INFINITE);
            rotateAnimator.setRepeatMode(ObjectAnimator.RESTART);
            rotateAnimator.setInterpolator(new LinearInterpolator());
            mAnimators.put(AnimationType.ROTATE,rotateAnimator);
        }
        rotateAnimator.setDuration(duration);

        curAnimationType = AnimationType.ROTATE;

        startAnimator(rotateAnimator);

    }

    /**
     * 播放心跳缩放动画
     */
    public void startHeartbeatAnimation(){
        if (isPlaying(AnimationType.HEARTBEAT))
            return;

        //先取消其它的动画
        if (curAnimationType != AnimationType.HEARTBEAT) {
            cancelAnimation();
        }

        ObjectAnimator heartbeatAnimator = mAnimators.get(AnimationType.HEARTBEAT);
        if (heartbeatAnimator == null){
            PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat(SCALE_X, 1f, 0.9f, 1f);
            PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat(SCALE_Y, 1f, 0.9f, 1f);
            heartbeatAnimator = ObjectAnimator.ofPropertyValuesHolder(this, scaleX, scaleY);
            heartbeatAnimator.setDuration(1000);
            heartbeatAnimator.setRepeatCount(ValueAnimator.INFINITE);
            heartbeatAnimator.setRepeatMode(ObjectAnimator.RESTART);
            heartbeatAnimator.setInterpolator(new LinearInterpolator());
            mAnimators.put(AnimationType.HEARTBEAT,heartbeatAnimator);
        }

        curAnimationType = AnimationType.HEARTBEAT;

        startAnimator(heartbeatAnimator);

    }

    /**
     * 是否正在播放
     */
    public boolean isPlaying(){
        return isPlaying(curAnimationType);
    }

    /**
     * 是否正在播放旋转动画
     */
    private boolean isPlaying(@Nullable AnimationType type) {
        if (type == null)
            return false;

        if (type == AnimationType.FRAME){
            Animatable animation = getAnimationDrawable();
            return animation != null && animation.isRunning();
        }

        ObjectAnimator rotateAnimator = mAnimators.get(type);
        return rotateAnimator != null && rotateAnimator.isRunning() && !rotateAnimator.isPaused();
    }

    /**
     * 暂停动画
     */
    public void pauseAnimator(){
        _pauseAnimator();
        isSysAutoPause = false;
        isSysAutoCancel = false;
    }


    private void _pauseAnimator() {
        if (curAnimationType == null)
            return;

        if (curAnimationType == AnimationType.FRAME){
            Animatable animation = getAnimationDrawable();
            if (animation != null && animation.isRunning()){
                animation.stop();
            }
            return;
        }

        ObjectAnimator animator = mAnimators.get(curAnimationType);
        if (animator != null && animator.isRunning()) {
            animator.pause();
        }
    }

    /**
     * 重新开始动画
     */
    public void restartAnimator(){
        isSysAutoPause = false;
        isSysAutoCancel = false;

        if (curAnimationType == null)
            return;

        if (curAnimationType == AnimationType.FRAME){
            Animatable animation = getAnimationDrawable();
            if (animation != null && animation.isRunning()){
                if (animation instanceof DrawableContainer){
                    ((DrawableContainer) animation).selectDrawable(0);
                }
                animation.start();
            }
            return;
        }


        ObjectAnimator animator = mAnimators.get(curAnimationType);
        if (animator == null)
            return;
        if(animator.isRunning())
            return;
        animator.start();
    }

    /**
     * 继续动画
     */
    public void resumeAnimator(){
        isSysAutoPause = false;
        isSysAutoCancel = false;

        if (curAnimationType == null)
            return;

        if (curAnimationType == AnimationType.FRAME){
            Animatable animation = getAnimationDrawable();
            if (animation != null && !animation.isRunning()){
                animation.start();
            }
            return;
        }

        ObjectAnimator animator = mAnimators.get(curAnimationType);
        if (animator != null){
            if (animator.isPaused()) {
                animator.resume();
            }
            else {
                animator.start();
            }
        }
    }

    /**
     * 取消动画
     */
    public void cancelAnimation(){
        _cancelAnimation();
        isSysAutoPause = false;
        isSysAutoCancel = false;
    }

    private void _cancelAnimation(){
        if (curAnimationType == null)
            return;

        if (curAnimationType == AnimationType.FRAME){
            Animatable animation = getAnimationDrawable();
            if (animation != null && animation.isRunning()){
                //停止帧动画
                animation.stop();
                //设置回第一帧
                if (animation instanceof DrawableContainer){
                    ((DrawableContainer) animation).selectDrawable(0);
                }
            }
            return;
        }

        ObjectAnimator animator = mAnimators.get(curAnimationType);
        if (animator != null && animator.isRunning()){
            //取消动画
            animator.cancel();
            //设置回第一帧
            animator.setCurrentPlayTime(0);
        }
    }

    @Nullable
    private Animatable getAnimationDrawable(){
        Drawable drawable = getDrawable();
        if (drawable == null)
            return null;
        if (drawable instanceof Animatable){
            return (Animatable) drawable;
        }
        return null;
    }

    @Override
    public void setImageDrawable(@Nullable Drawable drawable) {
        cancelAnimation();
        if(drawable != null){
            if (drawable instanceof Animatable){
                curAnimationType = AnimationType.FRAME;
            }
            else {
                curAnimationType = null;
            }
        }
        super.setImageDrawable(drawable);
    }

    public void setImageApng(@RawRes int resId){
        APNGDrawable drawable = new APNGDrawable(new ResourceStreamLoader(getContext(), resId));
        setImageDrawable(drawable);
    }

// 因为始终都会调用setImageDrawable，所以不需要重写setImageResource和setImageBitmap
//    @Override
//    public void setImageResource(int resId) {
//        cancelAnimation();
//        isSysAutoPause = false;
//        isSysAutoCancel = false;
//        super.setImageResource(resId);
//    }
//
//    @Override
//    public void setImageBitmap(Bitmap bm) {
//        cancelAnimation();
//        isSysAutoPause = false;
//        isSysAutoCancel = false;
//        super.setImageBitmap(bm);
//    }

    @Override
    protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
        super.onVisibilityChanged(changedView, visibility);
        if (curAnimationType == null)
            return;

        if (isShown()) {
            if (isSysAutoPause){
                isSysAutoPause = false;
                resumeAnimator();
            }
        }
        else {
            if(isPlaying()){
                isSysAutoPause = true;
                _pauseAnimator();
            }
        }
    }


    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (isSysAutoCancel){
            restartAnimator();
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (isPlaying()){
            isSysAutoCancel = true;
            _cancelAnimation();
        }
    }

    private enum AnimationType {
        FRAME, ROTATE, HEARTBEAT
    }

}
